package com.simple.framework.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.zuihou.base.R;
import com.github.zuihou.base.service.SuperServiceImpl;
import com.simple.business.domain.enumeration.ThirdAuthenticationEnum;
import com.simple.framework.utils.ThirdLoginUtils;
import com.simple.framework.web.domain.login.AuthUserThird;
import com.simple.framework.web.mapper.AuthUserThirdMapper;
import com.simple.framework.web.service.AuthUserThirdService;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.UuidUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;

@Slf4j
@Service
public class AuthUserThirdServiceImpl extends SuperServiceImpl<AuthUserThirdMapper, AuthUserThird> implements AuthUserThirdService {

        private static final String REDIS_AUTH_USER_BIND_CODE = "user_bing_code_";
    @Resource
    AuthUserThirdMapper authUserThirdMapper;

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    @Override
    public AuthUserThird getAuthUserInfo(String providerUserId, ThirdAuthenticationEnum provider) {
        AuthUserThird authUserInfo = authUserThirdMapper.selectOne(Wrappers.<AuthUserThird>lambdaQuery()
                .eq(AuthUserThird::getProviderUserId, providerUserId)
                .eq(AuthUserThird::getProviderName, provider.getProviderName()));
        return authUserInfo;
    }

    @Override
    public AuthUserThird insert(AuthUserThird authUserThird) {
        authUserThirdMapper.insert(authUserThird);
        return authUserThird;
    }


    @Override
    public R<AuthUserThird> getAuthUserByThirdCode(ThirdAuthenticationEnum provider, String code) {
        AuthRequest authRequest = ThirdLoginUtils.getAuthRequest(provider);
        if(authRequest == null){
            return R.fail("不支持此登录方式");
        }
        AuthCallback authCallback = AuthCallback.builder().code(code).auth_code(code).build();
        AuthResponse login = authRequest.login(authCallback);
        if(!login.ok()){
            log.error("第三方登录，请求失败：{}",login);
            return R.fail("请求失败，请重试");
        }
        if(!(login.getData() instanceof AuthUser)){
            log.error("第三方登录，对象类型错误：{}，错误类型为：{}",login,login.getData().getClass());
            return R.fail("数据出错");
        }
        if(provider == ThirdAuthenticationEnum.WEI_XIN_MINIPROGRAM || provider == ThirdAuthenticationEnum.WEI_XIN_MP){
            // 微信小程序归属于微信
            provider = ThirdAuthenticationEnum.WEI_XIN;
        }
        AuthUser authUser = (AuthUser)login.getData();
        AuthUserThird authUserInfo = getAuthUserInfo(authUser.getUuid(), provider);
        if (authUserInfo == null) {
            // 首次扫码，直接插入数据
            AuthUserThird build = AuthUserThird.builder()
                    .providerUserId(authUser.getUuid())
                    .providerUserOpenId(authUser.getRawUserInfo().getString("openid"))
                    .providerUserName(authUser.getNickname())
                    .providerName(provider.getProviderName()).build();
            insert(build);
            authUserInfo = build;
        }
        return R.success(authUserInfo);
    }

    @Override
    public String genAuthUserBindCode(AuthUserThird authUser) {
        String uuid = UuidUtils.getUUID();
        String key = REDIS_AUTH_USER_BIND_CODE + uuid;
        redisTemplate.opsForValue().set(key, authUser, Duration.ofMinutes(30));
        return uuid;
    }

    @Override
    public R<Boolean> bindUser(AuthUserThird authUserThird, Long userId) {
        AuthUserThird authUser = authUserThird;
        authUser.setUserId(userId);
        // 清除用户已有的绑定关系
        authUserThirdMapper.resetUserId(authUser);
        int updateResult = authUserThirdMapper.update(authUser, Wrappers.<AuthUserThird>lambdaUpdate()
                .eq(AuthUserThird::getProviderName, authUser.getProviderName())
                .eq(AuthUserThird::getProviderUserId, authUser.getProviderUserId()));
        if (updateResult > 0) {
            return R.success(true);
        }
        return R.fail("绑定失败，请重试");
    }

    @Override
    public R<Boolean> bindUser(ThirdAuthenticationEnum provider, String code, Long userId) {
        R<AuthUserThird> authUserByThirdCode = getAuthUserByThirdCode(provider, code);
        if (authUserByThirdCode.getIsError()) {
            return R.fail(authUserByThirdCode.getMsg());
        }
        AuthUserThird authUser = authUserByThirdCode.getData();
        authUser.setUserId(userId);
        // 清除用户已有的绑定关系
        authUserThirdMapper.resetUserId(authUser);
        int updateResult = authUserThirdMapper.update(authUser, Wrappers.<AuthUserThird>lambdaUpdate()
                .eq(AuthUserThird::getProviderName, authUser.getProviderName())
                .eq(AuthUserThird::getProviderUserId, authUser.getProviderUserId()));
        if (updateResult > 0) {
            return R.success(true);
        }
        return R.fail("绑定失败，请重试");
    }

    @Override
    public R<Boolean> cancelBind(Long userId, ThirdAuthenticationEnum thirdAuthenticationEnum) {
        LambdaUpdateWrapper<AuthUserThird> updateWrapper = Wrappers.<AuthUserThird>lambdaUpdate().
                eq(AuthUserThird::getUserId, userId)
                .eq(AuthUserThird::getProviderName,thirdAuthenticationEnum.getProviderName())
                .set(true,AuthUserThird::getUserId,null);
        update(updateWrapper);
        return R.success();
    }

    @Override
    public AuthUserThird getAuthUserThirdByUserId(Long userId,ThirdAuthenticationEnum thirdAuthenticationEnum) {
        return authUserThirdMapper.selectOne(Wrappers.<AuthUserThird>lambdaQuery()
                        .eq(AuthUserThird::getUserId, userId)
                        .eq(AuthUserThird::getProviderName, thirdAuthenticationEnum.getProviderName()));
    }
}
